package no.ntnu.fp.server;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import no.ntnu.fp.connection.Initializer;
import no.ntnu.fp.handler.Handler;
import no.ntnu.fp.handlers.AcceptNoticeHandler;
import no.ntnu.fp.handlers.AddMeetingHandler;
import no.ntnu.fp.handlers.AddOrUpdateAppointmentHandler;
import no.ntnu.fp.handlers.DeleteAppointmentHandler;
import no.ntnu.fp.handlers.DeleteMeetingHandler;
import no.ntnu.fp.handlers.GetEmployeesHandler;
import no.ntnu.fp.handlers.GetMeetingRoomsHandler;
import no.ntnu.fp.handlers.LoginHandler;
import no.ntnu.fp.handlers.LogoutHandler;
import no.ntnu.fp.handlers.MeetingRejectedHandler;
import no.ntnu.fp.handlers.NoticeReadHandler;
import no.ntnu.fp.handlers.RejectNoticeHandler;
import no.ntnu.fp.handlers.RequestAppointmentsForEmployeeHandler;
import no.ntnu.fp.handlers.RequestMeetingsForEmployeeHandler;
import no.ntnu.fp.handlers.UpdateMeetingHandler;
import no.ntnu.fp.handlers.exceptions.DatabaseException;
import no.ntnu.fp.messages.Message;
import no.ntnu.fp.messages.MessageCode;
import no.ntnu.fp.services.AppointmentService;
import no.ntnu.fp.services.EmployeeService;
import no.ntnu.fp.services.MeetingRoomService;
import no.ntnu.fp.services.MeetingService;
import no.ntnu.fp.services.NoticeService;
import no.ntnu.fp.services.impl.AppointmentServiceImpl;
import no.ntnu.fp.services.impl.EmployeeServiceImpl;
import no.ntnu.fp.services.impl.MeetingRoomServiceImpl;
import no.ntnu.fp.services.impl.MeetingServiceImpl;
import no.ntnu.fp.services.impl.NoticeServiceImpl;
import no.ntnu.fp.storage.impl.AppointmentStorageImpl;
import no.ntnu.fp.storage.impl.EmployeeStorageImpl;
import no.ntnu.fp.storage.impl.MeetingRoomStorageImpl;
import no.ntnu.fp.storage.impl.MeetingStorageImpl;
import no.ntnu.fp.storage.impl.NoticeStorageImpl;

/**
 * This class provides the different server {@link Handler}s of incoming 
 * {@link Message}s, and also general initialization. 
 * @author benjamin
 *
 */
public class InitializerImpl extends Initializer {
	
	private EmployeeStorageImpl employeeStorageImpl 
	= new EmployeeStorageImpl();
	private MeetingRoomStorageImpl meetingRoomStorageImpl 
	= new MeetingRoomStorageImpl();
	private AppointmentStorageImpl appointmentStorageImpl 
	= new AppointmentStorageImpl(employeeStorageImpl, meetingRoomStorageImpl);
	private MeetingStorageImpl meetingStorageImpl 
	= new MeetingStorageImpl(meetingRoomStorageImpl, employeeStorageImpl);
	private NoticeStorageImpl noticeStorageImpl 
	= new NoticeStorageImpl(meetingStorageImpl, employeeStorageImpl);

	private AppointmentService appointmentService 
						  = new AppointmentServiceImpl(appointmentStorageImpl);
	private EmployeeService employeeService 
								= new EmployeeServiceImpl(employeeStorageImpl);
	private MeetingRoomService meetingRoomService 
						= new MeetingRoomServiceImpl(meetingRoomStorageImpl);
	private MeetingService meetingService 
								= new MeetingServiceImpl(meetingStorageImpl);
	private NoticeService noticeService 
									= new NoticeServiceImpl(noticeStorageImpl, 
															meetingStorageImpl);
	
	
	
	@Override
	public void initialize() {
		super.initialize();
		try {
			Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
			Connection connection = DriverManager.getConnection("jdbc:derby:supersweetstorageplace");
			
			ConnectionProvider.initialize(connection);
		} catch (SQLException ex) {
			throw new DatabaseException("Could not initialize database connection", ex);
		} catch (Exception e) {
			throw new RuntimeException("Problem initializing derby driver", e);
		}
	}



	/**
	 * Returns a Map connecting {@link MessageCode}s and {@link Handler}s.<br/>
	 * An example implementation would look like:<br/>
	 * <code>
	 * 	Map map = new HashMap();
	 * 	map.put(MessageCode.SOME_CODE, new AppropriateHandler());
	 * 	return map;
	 * </code>
	 *  
	 */
	@Override
	protected Map<MessageCode, Handler> getMessageHandlers() {
		Map<MessageCode, Handler> map = new HashMap<MessageCode, Handler>();

		map.put(MessageCode.LOGIN_MESSAGE, 
				new LoginHandler(employeeService, noticeService, meetingService, appointmentService));
		map.put(MessageCode.LOGOUT_MESSAGE, new LogoutHandler());
		map.put(MessageCode.ADD_OR_UPDATE_APPOINTMENT_MESSAGE, new AddOrUpdateAppointmentHandler(appointmentService));
		map.put(MessageCode.GET_EMPLOYEES_MESSAGE, new GetEmployeesHandler(employeeService));
		map.put(MessageCode.GET_MEETING_ROOMS_MESSAGE, new GetMeetingRoomsHandler(meetingRoomService));
		map.put(MessageCode.NOTICE_READ_MESSAGE, new NoticeReadHandler(noticeService));
		map.put(MessageCode.DELETE_APPOINTMENT_MESSAGE, new DeleteAppointmentHandler(appointmentService));
		map.put(MessageCode.ADD_MEETING_MESSAGE, new AddMeetingHandler(meetingService, noticeService));
		map.put(MessageCode.UPDATE_MEETING_MESSAGE, new UpdateMeetingHandler(meetingService, noticeService));
		map.put(MessageCode.DELETE_MEETING_MESSAGE, new DeleteMeetingHandler(meetingService, noticeService));
		map.put(MessageCode.REQUEST_APPOINTMENTS_FOR_EMPLOYEE_MESSAGE, new RequestAppointmentsForEmployeeHandler(appointmentService));
		map.put(MessageCode.REQUEST_MEETINGS_FOR_EMPLOYEE_MESSAGE, new RequestMeetingsForEmployeeHandler(meetingService));
		map.put(MessageCode.ACCEPT_NOTICE_MESSAGE, new AcceptNoticeHandler(noticeService));
		map.put(MessageCode.REJECT_NOTICE_MESSAGE, new RejectNoticeHandler(noticeService));
		map.put(MessageCode.MEETING_REJECTED_MESSAGE, new MeetingRejectedHandler(meetingService, noticeService));
		
		return map;
	}
}
